/**
 * 加密工具
 */
import Md5 from 'crypto-js/Md5'
import DateUtil from '@/framework/utils/date-util'

const globalVal = globalThis as any;

const AuthEncrypt:any = {}

/**
 * 是否为数组
 */
function isArray (v:any):boolean {
  return toString.apply(v) === '[object Array]'
}

/**
 * uri
 * @param val
 * @param pctEncodeSpaces
 * @returns {string}
 */
AuthEncrypt.encodeUriQuery = function (val:string, pctEncodeSpaces?:boolean) {
  return encodeURIComponent(val)
    .replace(/%40/gi, '@')
    .replace(/%3A/gi, ':')
    .replace(/%24/g, '$')
    .replace(/%2C/gi, ',')
    .replace(/%20/g, (pctEncodeSpaces ? '%20' : '+'))
    .replace(/'/g, '%27')
}

AuthEncrypt.httpUrlFormat = function (urlOld:string, paramData:any, method:string) {
  if (paramData) {
    const urlArray:string[] = []

    paramData = isArray(paramData) ? (paramData.length > 0 ? paramData[0] : []) : paramData
    for (const key in paramData) {
      const value = paramData[key]
      if (isArray(value)) {
        if (method.toUpperCase() === 'GET' || method.toUpperCase() === 'DELETE') {
          const arrayValueCell:string[] = []
          for (const keyCell in value) {
            const valueCell = value[keyCell]
            arrayValueCell.push(key + '=' + AuthEncrypt.encodeUriQuery(valueCell))
          }
          if (arrayValueCell.length > 0) {
            urlArray.push(arrayValueCell.join('&'))
          }
        }
      } else {
        if (urlOld.indexOf(':' + key, value) !== -1) {
          urlOld = urlOld.replace(':' + key, AuthEncrypt.encodeUriQuery(value))
        } else {
          if (method.toUpperCase() === 'GET' || method.toUpperCase() === 'DELETE') {
            urlArray.push(key + '=' + AuthEncrypt.encodeUriQuery(value))
          }
        }
      }
    }

    urlArray.sort(function (a, b) {
      return a.localeCompare(b)
    })
    urlOld = encodeURI(urlOld) + (urlArray.length > 0 ? ('?' + urlArray.join('&')) : '')
  } else {
    urlOld = encodeURI(urlOld)
  }
  return (urlOld)
}

AuthEncrypt.encode = function (token:string, hmackey:string, method:string, uri:string, host:string, paramData:any, serverTime:number|null, localTime:number|null) {
  const rtnArray: string[] = []
  const sbRawMac: string[] = []
  const timestamp: number = serverTime && localTime ? new Date().getTime() + (serverTime - localTime) : new Date().getTime()
  const randomStr = Md5(Math.random().toString()).toString().substring(8, 16)
  const nonce = [timestamp, ':', randomStr].join('')
  sbRawMac.push(nonce)
  sbRawMac.push('\n')
  sbRawMac.push(method.toUpperCase())
  sbRawMac.push('\n')
  sbRawMac.push(AuthEncrypt.httpUrlFormat(uri, paramData, method))
  sbRawMac.push('\n')
  sbRawMac.push(host)
  sbRawMac.push('\n')

  const text = Md5(sbRawMac.join('') + '{' + hmackey + '}').toString()
  rtnArray.push('MAC id="')
  rtnArray.push(token)
  rtnArray.push('",nonce="')
  rtnArray.push(nonce)
  rtnArray.push('",mac="')
  rtnArray.push(text)
  rtnArray.push('"')

  return rtnArray.join('')
}

/**
 * 获取MAC
 */
AuthEncrypt.getMac = function (method:string, url:string, token:any, paramData:any) {
  if (token == null) {
    return ''
  }
  url = decodeURIComponent(url)
  url = url.replace(/^(http|https):\/\//, '')
  const pos = url.indexOf('/')
  const host = url.substr(0, pos)
  let uri = url.substring(pos)
  if(globalVal.API_URI_PREFIX && uri.startsWith(globalVal.API_URI_PREFIX)){
  	  uri = uri.substring(globalVal.API_URI_PREFIX.length)
  }
  return AuthEncrypt.encode(token.access_token, token.mac_key, method, uri, host, paramData, DateUtil.toDate(token.server_time), DateUtil.toDate(token.local_time))
}

export default AuthEncrypt
